﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Itfort
{
	/// <summary>
	/// 将对象从一种对象类型转换为另一种对象类型。
	/// </summary>
	public static class ObjectConverter
	{
		/// <summary>
		/// 类型属性字典的全局缓存
		/// </summary>
		private static Dictionary<Type, TypePropertyDictionary> TypePropertyDictionaryCache = new Dictionary<Type, TypePropertyDictionary>();

		/// <summary>
		/// 通过属性匹配的方式，将Source对象转换成Target对象。
		/// </summary>
		/// <param name="sourceObject">来源对象实例。</param>
		/// <param name="sourceObjectType">来源对象类型。</param>
		/// <param name="targetObjectType">目标对象类型。</param>
		/// <returns></returns>
		public static Object Convert(Object sourceObject, Type sourceObjectType, Type targetObjectType)
		{
			if (sourceObject == null) return null;

			Object targetObject = Activator.CreateInstance(targetObjectType);
			var sourceTypePropertyDictionary = GetTypePropertyDictionary(sourceObjectType);
			var targetTypePropertyDictionary = GetTypePropertyDictionary(targetObjectType);
			foreach (var sourceKeyValueProperty in sourceTypePropertyDictionary)
			{
				string propertyName = sourceKeyValueProperty.Key;
				PropertyInfo sourceProperty = sourceKeyValueProperty.Value;
				// 属性不可读
				if (!sourceProperty.CanRead) continue;
				PropertyInfo targetProperty;
				if (targetTypePropertyDictionary.TryGetValue(propertyName, out targetProperty))
				{
					// 属性不可写
					if (!targetProperty.CanWrite) continue;
					var propertyValue = sourceProperty.GetValue(sourceObject, null);
					targetProperty.SetValue(targetObject, propertyValue, null);
				}
			}
			return targetObject;
		}

		/// <summary>
		/// 通过属性匹配的方式，将Source对象转换成Target对象。
		/// </summary>
		/// <param name="sourceObject">来源实例对象。</param>
		/// <param name="targetObjectType">目标对象类型。</param>
		/// <returns></returns>
		public static Object Convert(Object sourceObject, Type targetObjectType)
		{
			if (sourceObject == null) return null;
			
			Type sourceObjectType = sourceObject.GetType();
			return Convert(sourceObject, sourceObjectType, targetObjectType);
		}

		/// <summary>
		/// 通过属性匹配的方式，将Source对象转换成Target对象。
		/// </summary>
		/// <typeparam name="TTarget">目标对象类型。</typeparam>
		/// <param name="sourceObject">来源实例对象。</param>
		/// <returns></returns>
		public static TTarget Convert<TTarget>(Object sourceObject)
		{
			return (TTarget)Convert(sourceObject, typeof(TTarget));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="TSource"></typeparam>
		/// <typeparam name="TTarget"></typeparam>
		/// <param name="sourceList"></param>
		/// <returns></returns>
		public static List<TTarget> Convert<TSource, TTarget>(IList<TSource> sourceList)
		{
			List<TTarget> targetList = new List<TTarget>();

			foreach (var source in sourceList)
			{
				var target = (TTarget)Convert(source, typeof(TSource), typeof(TTarget));
				targetList.Add(target);
			}

			return targetList;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="sourceList"></param>
		/// <returns></returns>
		public static List<T> Convert<T>(IEnumerable sourceList)
		{
			List<T> targetList = new List<T>();

			foreach (var source in sourceList)
			{
				var target = Convert<T>(source);
				targetList.Add(target);
			}

			return targetList;
		}

		/// <summary>
		/// 获取类型属性字典。
		/// </summary>
		/// <param name="type">类型实例。</param>
		/// <returns>返回类型实例的公开实例属性。</returns>
		public static TypePropertyDictionary GetTypePropertyDictionary(Type type)
		{
			TypePropertyDictionary typePropertyDictionary;
			if (!TypePropertyDictionaryCache.TryGetValue(type, out typePropertyDictionary))
			{// 全局缓存中不存在类型的属性集
				typePropertyDictionary = new TypePropertyDictionary();
				var list = type.GetProperties();
				foreach (var item in list)
				{
					typePropertyDictionary.Add(item.Name, item);
				}
				TypePropertyDictionaryCache[type] = typePropertyDictionary;
			}
			return typePropertyDictionary;
		}

		/// <summary>
		/// 类型属性字典
		/// </summary>
		public class TypePropertyDictionary : Dictionary<string, PropertyInfo>
		{

		}
	}
}
